package bitmap

import (
	"database/sql/driver"
	"strconv"
)

func NewBitMap(size int) *BitMap {
	if size < 0 {
		panic("bitmap size < 0")
	}
	bm := &BitMap{
		bits: nil,
		size: size,
	}
	ci, _ := bm.getByteIndex(size - 1)
	bm.bits = make([]byte, ci+1)
	return bm
}

type BitMap struct {
	bits []byte
	size int
}

func (b *BitMap) GetBit(bitIndex int) bool {
	if bitIndex < 0 || bitIndex >= b.size {
		return false
	}
	ci, bi := b.getByteIndex(bitIndex)
	return b.bits[ci]&1<<bi != 0
}

func (b *BitMap) getByteIndex(bitIndex int) (int, int) {
	return bitIndex / 8, bitIndex % 8
}

func (b *BitMap) SetBit(bitIndex int, on bool) {
	ci, bi := b.getByteIndex(bitIndex)

	if on {
		b.bits[ci] = b.bits[ci] | (1 << bi)
	} else {
		b.bits[ci] = b.bits[ci] & ^(1 << bi)
	}
}

// Scan implements the Scanner interface.
func (b *BitMap) Scan(value any) error {
	if value == nil {
		b.bits, b.size = make([]byte, 0), 0
		return nil
	}
	switch s := value.(type) {
	case string:
		str := s
		length := len(str)
		b.size = length * 4
		b.bits = make([]byte, (b.size/8)+1)
		for i := 0; i < length; i += 2 {
			bi := (length - i) / 2
			by := str[i : i+2]
			in, err := strconv.ParseUint(by, 16, 0)
			if err != nil {
				return err
			}
			b.bits[bi] = byte(in)
		}
	case []byte:
		str := string(s)
		length := len(str)
		b.size = length * 4
		b.bits = make([]byte, (b.size/8)+1)
		for i := 0; i < length; i += 2 {
			bi := (length - i) / 2
			by := str[i : i+2]
			in, err := strconv.ParseUint(by, 16, 0)
			if err != nil {
				return err
			}
			b.bits[bi] = byte(in)
		}
	case int:
	}
	return nil
}

// Value implements the driver Valuer interface.
func (b BitMap) Value() (driver.Value, error) {
	return nil, nil
}
